/*
 * Copyright 2008 Lucas Tan.
 * This copyright notice must always remain intact whenever you use or distribute 
 * the source code contained in this file.
 * Any usage of any code in this file, either in derived work or
 * through the use of external linkage,
 * must always be credited with the author's name.
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 * 
 * */
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using PassKeeper.Gui;
using PassKeeper.Cryptography;
using System.Security.Cryptography;

namespace PassKeeper
{
	internal static class Program
	{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		private static void Main()
		{
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new PassKeeper.Gui.Main());

			//cipherTest();

			//perfTest(1000, 4096, CipherMode.ECB, PaddingMode.None);
			//perfTest(1000, 4096, CipherMode.CBC, PaddingMode.None);
			//perfTest(10000, 400, CipherMode.CBC, PaddingMode.PKCS7);
			//perfTest(10000, 401, CipherMode.CBC, PaddingMode.PKCS7);

		}

		private static double[]/*millisec*/ perfTest(int iteration, int datasize, SymmetricAlgorithm sa)
		{
			ICryptoTransform t = sa.CreateEncryptor();

			byte[] b = new byte[datasize];
			RNG.GetBytes(b);

			DateTime s = DateTime.Now;

			for (int i = 0; i <iteration; i++)
			{
				t.TransformFinalBlock(b, 0, b.Length);
			}

			DateTime e = DateTime.Now;

			b = t.TransformFinalBlock(b,0,b.Length);
			t.Dispose();
			TimeSpan span = e - s;
			double t1= (double)span.Ticks / TimeSpan.TicksPerMillisecond;


			////////////////////////////////////////////

			  t =   sa.CreateDecryptor();

		
			  s = DateTime.Now;

			for (int i = 0; i < iteration; i++)
			{
				t.TransformFinalBlock(b, 0, b.Length);
			}

			  e = DateTime.Now;

			t.Dispose();
			 span = e - s;
			double t2 = (double) span.Ticks / TimeSpan.TicksPerMillisecond;

			return new double[]{t1,t2};
		}

		private static void perfTest(int iteration, int datasize, CipherMode mode, PaddingMode padding)
		{
			AESManaged a = new AESManaged();
			RijndaelManaged r = new RijndaelManaged();
			r.BlockSize = 128;
			r.FeedbackSize = 128;
			a.KeySize = r.KeySize = 256;
			a.Mode = r.Mode =mode;
			a.Padding = r.Padding =padding;

			a.GenerateIV();
			r.IV = a.IV;
			a.GenerateKey();
			r.Key = a.Key;

			double[]k1 = perfTest(iteration,datasize,a);
 
			double[]k2 =perfTest(iteration,datasize,r);

			MessageBox.Show(
				string.Format(@"cipher mode = {6}
padding = {7}
Iteration Count = {0}
Data Size Bytes = {1}

AES Encruyption Time = {2} millisec
AES Decruyption Time = {3} millisec
R Encruyption Time = {4} millisec
R Decruyption Time = {5} millisec
",iteration,datasize,
 k1[0],k1[1],k2[0],k2[1],mode,padding

 )
 );


			((IDisposable) a).Dispose();
			((IDisposable) r).Dispose();
			
		}

		private static void cipherTest()
		{
			AESManaged a = new AESManaged();
			RijndaelManaged r = new RijndaelManaged();

			r.BlockSize = 128;
			r.FeedbackSize = 128;

			test1(a, r, PaddingMode.ANSIX923);
			test1(a, r, PaddingMode.ISO10126);
			test1(a, r, PaddingMode.PKCS7);

			MessageBox.Show("ok");

			((IDisposable) a).Dispose();
			((IDisposable) r).Dispose();
			
		}

		private static void test1(AESManaged a, RijndaelManaged r, PaddingMode padding)
		{
			a.Padding = padding;
			r.Padding = padding;


			test(a, r, 128);
			test(a, r, 192);
			test(a, r, 256);
		}

		private static void test(AESManaged a, RijndaelManaged r, int keySize)
		{
			a.KeySize = keySize;
			r.KeySize = keySize;
			a.GenerateKey();
			r.Key = a.Key;

			a.GenerateIV();
			r.IV = a.IV;

			test2(a, r, CipherMode.ECB);
			test2(a, r, CipherMode.CBC);
			test2(a, r, CipherMode.CFB);
			test2(a, r, CipherMode.OFB);
		}

	
		private static void test2(AESManaged a, RijndaelManaged r, CipherMode mode)
		{

			a.Mode = mode;
			r.Mode = mode;

			ICryptoTransform a_enc = a.CreateEncryptor();
			ICryptoTransform a_dec = a.CreateDecryptor();

			ICryptoTransform r_enc = null;
			
			ICryptoTransform r_dec = null;

			if (mode != CipherMode.OFB)
			{
				r_dec = r.CreateDecryptor();
				r_enc = r.CreateEncryptor();
			}

			for (int i = 0; i <= 128; i++)
			{

				byte[] data = new byte[i];
				if (i < 128)
				{
					RNG.GetBytes(data);
				}
				else
				{
					data = new byte[256];
					for (int n = 0; n < 256; n++)
					{
						data[n] = (byte) n;
					}
				}

				byte []ad = a_enc.TransformFinalBlock(data, 0, data.Length);

				byte[] rd = ad;
				if (mode != CipherMode.OFB)
				{
					rd = r_enc.TransformFinalBlock(data, 0, data.Length);
				}

				if (a.Padding !=PaddingMode.ISO10126 && !Equals(ad, rd))
				{
					Notify(0,a, r, data.Length);
				}

				byte []adec = a_dec.TransformFinalBlock(ad, 0, ad.Length);

				if (mode != CipherMode.OFB)
				{
					byte[] rdec = r_dec.TransformFinalBlock(rd, 0, rd.Length);
					if (  !Equals(adec, rdec))
					{
						Notify(2, a, r, data.Length);
					}
				}

				if (!Equals(data, adec))
				{
					Notify(1,a, r, data.Length);
				}
				
			}

			a_enc.Dispose();
			a_dec.Dispose();
			if (mode != CipherMode.OFB)
			{
				r_enc.Dispose();
				r_dec.Dispose();
			}
		}

		private static void Notify(int k, AESManaged a, RijndaelManaged r, int len)
		{
			MessageBox.Show(
				
				string.Format(
				@"{4} 

keysize = {0}
padding = {1}
mode = {2}
len = {3}
", a.KeySize,a.Padding ,a.Mode,len ,k

				)
				
				);
		}

		private static bool Equals(byte[] a, byte[] b)
		{
			if ((a == null && b != null) || (a != null && b == null))
			{
				return false;
			}

			if (a.Length != b.Length)
			{
				return false;
			}

			for (int i = 0; i < a.Length; i++)
			{
				if (a[i] != b[i])
				{
					return false;
				}
			}

			return true;
		}
	}
}